home *** CD-ROM | disk | FTP | other *** search
- #define SWITCH
- /* laplace - solve Laplace's equation for specified boundary conditions
- in two dimensions
-
- history...
- 28 Jun 86 -g switch sets edge of grid to zero potential,
- -m switch specifies a margin around the specified boundaries.
- 21 Jun 86 Allowing boundary to be between grid points.
- 31 May 86 showing boundries and calculated potentials are optional.
-
- approximate performance...
-
- h=w=32, n=64
- Current time is 20:58:25.76
-
- Current time is 21:00:03.36
-
-
- h=w=64, n=128
- Current time is 21:01:11.29
-
- Current time is 21:07:08.87
-
- ...producing 42K file
-
- ...on Z-100 with V20 at 7.5 MHz, all files on ramdisk.
-
- notes...
- need to update above performance.
- should investigate recursive subdivision by factors other than 2.
- needs -m switch to specify a margin (for expanding the x & y range)
- can't handle boundary crossing edge of grid: referencing nonexistant
- grid points.
- needs option for cylindrical symmetry
-
- */
- #define DESMET /* deleting this only disables the timing function */
-
- #include <stdio.h>
- #include <math.h>
-
- #define VERSION "0.2"
- #define MAX_CROSS 300 /* max # times boundary can cross grid */
- #define ENTRIES 300 /* maximum # points in boundary point curves */
- #define MAXBOUNDARIES 50 /* maximum # separate curves in boundary */
- #define PERMITTIVITY 8.85418e-12 /* permittivity of free space, farad/m */
- #define SCALE 256
- #define MAX(a,b) ((a)>(b)?(a):(b))
-
- typedef struct
- {int grid; /* cell number */
- int direct; /* direction: 0, 1, 2, 3 for +x, -x, +y, -y */
- double dist; /* distance from cell center and boundary crossing point
- (fraction of grid spacing) */
- int volt; /* negative of boundary # (so it's an index into volt[]) */
- int dummy[4]; /* ...so sizeof(crossing) >= sizeof(boundary_rule) */
- } crossing;
-
- typedef struct
- {int var[4]; /* grid number on which this point depends */
- int coef[4]; /* corresponding coefficient, scaled up by SCALE */
- } boundary_rule;
-
- union /* these can share space */
- {boundary_rule b_rule[MAX_CROSS];
- crossing cross_list[MAX_CROSS];
- } bo;
-
- show_b(b) boundary_rule *b;
- { int i, sum;
- sum=0;
- for (i=0; i<4; i++) sum += b->coef[i];
- printf("rule %d: <%2d>*%d+<%2d>*%d+<%2d>*%d+<%2d>*%d (ttl wt=%d)\n",
- b-bo.b_rule,
- b->var[0],b->coef[0],
- b->var[1],b->coef[1],
- b->var[2],b->coef[2],
- b->var[3],b->coef[3],
- sum);
- i=0;
- }
-
- char *c_label[4]={"right of","left of","above","below"};
- show_c(c) crossing *c;
- { printf("boundary value %d is %f %s grid %d\n",
- c->volt, c->dist, c_label[c->direct], c->grid);
- }
-
-
- int lc; /* index of 1st unused entry in bo.cross_list */
- int lb; /* index of 1st unused entry in bo.b_rule */
-
- /*
- cell types are as follows...
-
- 2 3 3 3 4
- 9 1 1 1 5
- 9 1 1 1 5
- 9 1 1 1 5
- 8 7 7 7 6
-
- ...and type 0 cells have a specified potential (part of the
- boundary conditions) and are never updated. There are special cell
- types are for boundaries where the normal gradient vanishes:
-
- 10 10 10 10
- 13 11
- 13 11
- 13 11
- 12 12 12 12
- */
- int alpha=0, alphap1=1;
- int *type; int *volt;
- int debugging=0;
- int show_resid=0; /* nonzero if residuals are to be shown */
- int grounded=0; /* nonzero if edge of grid is to be grounded */
- int show_boundaries=0; /* nonzero if boundaries are to be shown */
- int show_potentials=0; /* nonzero if calculated potentials are to be shown */
- int left_symmetric=0; /* nonzero if x gradient vanishes on left edge of grid */
- int lower_symmetric=0; /* nonzero if y gradient vanishes on lower edge of grid */
- int done=0;
- long work=0; /* number of cell updates so far */
-
- double xmin=1.e30;
- double xmax=-1.e30;
- double ymin=1.e30;
- double ymax=-1.e30;
- double zmin=1.e30;
- double zmax=-1.e30;
- double margin=0.; /* minimum amount to expand grid beyond given boundaries */
- double *x; /* pointer to data area for boundaries */
- double *y; /* pointer to data area for boundaries */
- double xscale,yscale,zscale;
- double edge;
- double aspect,correct;
- double p_voltage[MAXBOUNDARIES];
- double residual();
-
- int boundaries=0; /* number of boundaries in input data */
- int x_arguments=0;
- int y_arguments=0;
- int height=32; /* default height of grid in cells */
- int width=32; /* default width of grid in cells */
- int cycles=64; /* default # relaxation cycles */
- int n; /* number of entries in x and y */
- int index_array[MAXBOUNDARIES]; /* indexes into x and y */
- int *p_data=index_array;
- char outname[40];
-
- FILE file;
- FILE ofile;
-
-
- main (argc,argv) int argc; char **argv;
- { int i,j,k,hw,col;
- double yval;
- char *s;
- read_data(argc,argv);
- /*
- printf("there are %d points...\n",n);
- k=0;
- for (i=0; i<n; i++)
- {printf("%f %f\n",x[i],y[i]);
- if(i==p_data[k]) printf(" ...at voltage %f\n",p_voltage[k++]);
- }
- */
- if(s=index(argv[1],'.')) strncpy(outname,argv[1],s-argv[1]);
- else strcpy(outname,argv[1]);
- strcat(outname,".pot");
- ofile=fopen(outname,"w");
- if(ofile==0) {printf("can\'t create output file\n"); exit(1);}
- aspect=(ymax-ymin)/(xmax-xmin);
- if(height<width*aspect) height=width*aspect;
- else width=height/aspect;
- if(height<width*aspect)
- {correct=(ymax-ymin)*width/(double)height-(xmax-xmin);
- xmin -= correct/2.;
- xmax += correct/2.;
- }
- else
- {correct=(xmax-xmin)*height/(double)width-(ymax-ymin);
- ymin -= correct/2.;
- ymax += correct/2.;
- }
- hw=height*width;
- if(cycles<height) cycles=height;
- if(cycles<width) cycles=width;
- printf("x in (%g,%g) and y in (%g,%g)\n",xmin,xmax,ymin,ymax);
- type=malloc(hw*sizeof(int));
- volt=malloc((boundaries+hw)*sizeof(int));
- if(!type || !volt)
- {fprintf(stderr,"not enough workspace for %d by %d grid",height,width);
- exit(1);
- }
- volt += boundaries; /* allow space for the boundary potentials */
- laplace(type,volt,width,height,cycles);
- if(show_potentials) show_volt(type,volt,width,height);
- #ifdef FIXED
- charges(type,volt,width,height);
- #endif
- printf("writing result to file %s\n",outname);
- if(-1==fprintf(ofile,"%10.4g%10.4g%5d minimum and maximum x values, width\n",xmin,xmax,width)) exit(1);
- if(-1==fprintf(ofile,"%10.4g%10.4g%5d minimum and maximum y values, height\n",ymin,ymax,height)) exit(1);
- yval=ymin;
- for (i=0; i<height; i++)
- {col=0;
- for (j=0; j<width; j++)
- {if(-1==fprintf(ofile,"%10.4g",volt[i*width+j]/zscale+zmin)) exit(1);
- if(++col>=7)
- {if(-1==fprintf(ofile,"\n")) exit(1);
- col=0;
- }
- }
- if(col)
- if(-1==fprintf(ofile,"\n")) exit(1);
- }
- fclose(ofile);
- }
-
- laplace (type,volt,width,height,cycles) int *type; int *volt,width,height,cycles;
- {
- #ifdef DESMET
- long start,tics();
- #endif
- int i,j,k,hw;
- hw=height*width;
- if(height>width) i=height;
- else i=width;
- if(i>=8 && (width&1)==0 && (height&1)==0)
- {laplace(type,volt,width/2,height/2,cycles/2);
- i=hw; j=i/4;
- while(i)
- {i--; j--;
- volt[i]=volt[i-1]=volt[i-width]=volt[i-width-1]=volt[j];
- i--;
- if(i%width==0) i -= width;
- }
- }
- else
- {for (i=0; i<hw; i++) volt[i]=4096;
- }
- printf("height=%d, width=%d, cycles=%d\n",height,width,cycles);
- #ifdef DESMET
- start=tics();
- #endif
- fill(type,volt,width,height);
- k=0;
- if(show_boundaries)
- {for (i=height-1; i>=0; i--)
- {k=i*width;
- printf("%3d: ",i);
- for (j=0; j<width; j++)
- printf("%3d",type[k++]);
- printf("\n");
- }
- if(debugging) getchar();
- }
- /* show_volt(type,volt,width,height); */
- while(cycles>-1)
- {while(!csts() && cycles--)
- {if(!show_resid)
- printf("\015 %d cycles to go ",cycles);
- relax(type,volt,width,height);
- work += hw;
- if(show_resid && ++done%5==0)
- printf("%D %f\n",work,residual(type,volt,width,height));
- }
- if(cycles>-1)
- {printf("\nINTERRUPTED ");
- show_volt(type,volt,width,height);
- printf("continue calculation (Y/N)? ");
- if(toupper(getchar())!='Y')break;
- }
- }
- #ifdef DESMET
- printf("\015 finished in %4.2f sec \n",.01*(tics()-start));
- #else
- printf("\015 finished \n");
- #endif
- }
-
- relax (type,v,w,h) int *type; int *v,w,h;
- { int i,wh;
- int hm1,wm1,j;
- boundary_rule *rule;
- long sum;
-
- #ifdef SWITCH
- i=wh=w*h;
- while(i--)
- {if(*type>0)
- {switch(*type)
- {
- case 1: v[0]= ( v[-w] + v[-1] + v[1] + v[w] + 2)/4; break;
- case 2: v[0]= ( v[1] + v[w] + 1)/2; break;
- case 3: v[0]= ( 2*v[-1] + 2*v[1] + v[w] + 2)/5; break;
- case 4: v[0]= ( v[-1] + v[w] + 1)/2; break;
- case 5: v[0]= (2*v[-w] + v[-1] + 2*v[w] + 2)/5; break;
- case 6: v[0]= ( v[-w] + v[-1] + 1)/2; break;
- case 7: v[0]= ( v[-w] + 2*v[-1] + 2*v[1] + 2)/5; break;
- case 8: v[0]= ( v[-w] + v[1] + 1)/2; break;
- case 9: v[0]= (2*v[-w] + v[1] + 2*v[w] + 2)/5; break;
- case 10: v[0]= (2*v[ w] + v[-1] + v[1] + 2)/4; break;
- case 11: v[0]= ( v[-w] + 2*v[-1] + v[ w] + 2)/4; break;
- case 12: v[0]= ( v[-1] + v[1] + 2*v[-w] + 2)/4; break;
- case 13: v[0]= ( v[-w] + 2*v[1] + v[ w] + 2)/4; break;
- }
- }
- else if (*type<0)
- {rule=&bo.b_rule[-*type];
- sum=0L;
- #ifdef DEBUG
- printf("\ngrid %d: ",wh-i-1); show_b(rule);
- show_volt(type,volt,w,h);
- #endif
- for (j=0; j<4; j++) sum += volt[rule.var[j]]*(long)rule.coef[j];
- v[0]=sum/SCALE;
- #ifdef DEBUG
- printf("setting potential to %5.2f\n",v[0]/zscale+zmin);
- #endif
- }
- v++; type++;
- }
- #else
- hm1=h-1;
- wm1=w-1;
- if(*type++)
- v[0]= ( v[1] + v[w] + 1)/2;
- v++;
- for (j=1; j<wm1; j++)
- {if(*type++)
- v[0]= ( v[-1] + v[1] + v[w] + 1)/3;
- v++;
- }
- if(*type++)
- v[0]= ( v[-1] + v[w] + 1)/2;
- v++;
- for (i=1; i<hm1; i++)
- {
- if(*type++)
- v[0]= (v[-w] + v[1] + v[w] + 1)/3;
- v++;
- for (j=1; j<wm1; j++)
- {if(*type++)
- v[0]= (v[-w] + v[-1] + v[1] + v[w] + 2)/4;
- v++;
- }
- if(*type++)
- v[0]= (v[-w] + v[-1] + v[w] + 1)/3;
- v++;
- }
- if(*type++)
- v[0]= (v[-w] + v[1] + 1)/2;
- v++;
- for (j=1; j<wm1; j++)
- {if(*type++)
- v[0]= (v[-w] + v[-1] + v[1] + 1)/3;
- v++;
- }
- if(*type++)
- v[0]= (v[-w] + v[-1] + 1)/2;
- v++;
-
- #endif
- }
-
- double residual (type,volt,w,h) int *type; int *volt,w,h;
- { int i,hw,n;
- int hm1,wm1,j;
- long r,d;
-
- n=0;
- i=hw=w*h;
- r=0L;
- while(i--)
- {switch(*type++)
- {case 0: n++; break;
- case 1: d=volt[0]-(volt[-w] + volt[-1] + volt[1] + volt[w] + 2)/4; r+=d*d; break;
- case 2: d=volt[0]-( volt[1] + volt[w] + 1)/2; r+=d*d; break;
- case 3: d=volt[0]-( volt[-1] + volt[1] + volt[w] + 1)/3; r+=d*d; break;
- case 4: d=volt[0]-( volt[-1] + volt[w] + 1)/2; r+=d*d; break;
- case 5: d=volt[0]-(volt[-w] + volt[-1] + volt[w] + 1)/3; r+=d*d; break;
- case 6: d=volt[0]-(volt[-w] + volt[-1] + 1)/2; r+=d*d; break;
- case 7: d=volt[0]-(volt[-w] + volt[-1] + volt[1] + 1)/3; r+=d*d; break;
- case 8: d=volt[0]-(volt[-w] + volt[1] + 1)/2; r+=d*d; break;
- case 9: d=volt[0]-(volt[-w] + volt[1] + volt[w] + 1)/3; r+=d*d; break;
- }
- volt++;
- }
- if (hw<=n)
- return 1.;
- return sqrt(((double)r)/(hw-n));
- }
-
- #ifdef FIXED
- /*
- this no longer works...could be changed to solve linear system for
- the gradient at center of each grid point next to a boundary and
- integrate, but it's easier to let CONTOUR calculate the integral.
- */
- charges (type,volt,width,height) int *type; int *volt,width,height;
- { int v,i,plate=0,out=0,hw;
- long charge;
- double C,Z,q[2],plate_voltage[2],sum=0.;
- hw=height*width;
- printf("\nComputing surface integral of grad V over each boundary\n");
- printf("(integral of -grad V dot N, where N is normal to the boundary)...\n");
- printf("\nboundary potential surface integral charge\n");
- while(1)
- {for (i=0; i<hw; i++)
- if(type[i]==0)
- break;
- if(i==hw) break;
- v=volt[i];
- plate_voltage[plate&1]=v/zscale+zmin;
- charge=0.;
- if(i%width) charge += v-volt[i-1];
- if(i>=width) charge += v-volt[i-width];
- if(i<hw-width) charge += v-volt[i+width];
- if(i%width != width-1) charge += v-volt[i+1];
- type[i]=23;
- for (i++; i<hw; i++)
- {if(type[i]==0 && v==volt[i])
- {if(i%width) charge += v-volt[i-1];
- if(i>=width) charge += v-volt[i-width];
- if(i<hw-width) charge += v-volt[i+width];
- if(i%width != width-1) charge += v-volt[i+1];
- type[i]=23; /* don't look at this cell again */
- }
- }
- sum += (q[plate&1]=(charge/zscale)*PERMITTIVITY);
- printf("%5d %14.2g %15.3g %15.3g\n",
- plate,v/zscale+zmin,q[plate&1]/PERMITTIVITY,q[plate&1]);
- plate++;
- }
- printf(" sum (should be zero)%12.3g %15.3g\n\n",sum/PERMITTIVITY,sum);
- if(plate==2)
- {q[0]=fabs(q[0]);
- q[1]=fabs(q[1]);
- C=MAX(q[1],q[0])/fabs(plate_voltage[1]-plate_voltage[0]);
- Z=1./C/2.9979e8;
- printf("characteristic impedance is %5.2f ohms\n",Z);
- printf("capacitance is %7.3g farad/m\n",C);
- printf("inductance is %7.3g henries/m\n",Z/2.9979e8);
- }
- }
- #endif
- /*
- the equations relating a grid point and its four neighbors, in the
- absence of a boundary, is:
-
- ( 0 1 1 1) (Ux ) (Uright)
- ( 0 -1 1 1) (Uy ) = (Uleft )
- ( 1 0 -1 1) (Uxx ) (Uup )
- (-1 0 -1 1) (Uhere) (Udown )
-
- where Ux is h*(d/dx U)
- Uy is h*(d/dy U)
- Uxx is .5*h**2*(d^2/dx^2 U))
- */
-
- double lhs[16]=
- {0., 1., 1., 1.,
- 0.,-1., 1., 1.,
- 1., 0.,-1., 1.,
- -1., 0.,-1., 1.};
-
- #define LEFT_SIDE(g) ((g)%w==0)
- #define RIGHT_SIDE(g) ((g)%w==w-1)
- #define TOP_SIDE(g) ((g)<w)
- #define LOWER_SIDE(g) ((g)>=hw-w)
-
- /* fill type and voltage arrays based on user's boundary conditions */
- fill (type,volt,w,h) int *type; int *volt,w,h;
- { boundary_rule *ru;
- crossing *this,*last;
- double invert(), decomp();
- double a[4][4], ai[4][4], cond, condp1, *p, f;
- double xt,yt,xt2,yt2;
- int i,j,g,weight,zero;
- int compare();
- int i,k,hw,zz;
-
- printf("establishing boundary conditions\n");
- hw=h*w;
- xscale=(w-1)/(xmax-xmin);
- yscale=(h-1)/(ymax-ymin); /* same as xscale */
- edge=1./xscale;
- /* printf("xscale=%f, yscale=%f, edge=%f\n",xscale,yscale,edge); */
- zscale=32760./5./(zmax-zmin);
-
- for (i=0; i<hw; i++) type[i]=1; /* interior */
- if(grounded)
- {zero=floor((0.-zmin)*zscale+.499);
- for (i=w; i<hw; i+=w) {type[i]=0; volt[i]=zero;} /* left */
- for (i=0; i<w; i++) {type[i]=0; volt[i]=zero;} /* top */
- for (i=w-1; i<hw; i+=w) {type[i]=0; volt[i]=zero;} /* right */
- for (i=hw-w; i<hw; i++) {type[i]=0; volt[i]=zero;} /* bottom */
- }
- else
- {if(left_symmetric)
- for (i=w; i<hw; i+=w) type[i]=13; /* left */
- else
- for (i=w; i<hw; i+=w) type[i]=9; /* left */
- for (i=0; i<w; i++) type[i]=3; /* top */
- for (i=w-1; i<hw; i+=w) type[i]=5; /* right */
- if(lower_symmetric)
- for (i=hw-w; i<hw; i++) type[i]=12; /* bottom */
- else
- for (i=hw-w; i<hw; i++) type[i]=7; /* bottom */
- type[0]=2; type[w-1]=4; type[hw-w]=8; type[hw-1]=6; /* corners */
- }
- i=k=0;
- lc=2; /* bo.cross_list is empty */
- while(i<n)
- {xt=x[i]-xmin;
- yt=y[i]-ymin;
- zz=floor((p_voltage[k]-zmin)*zscale+.499);
- volt[-k-1]=zz;
- do {xt2=x[i]-xmin;
- yt2=y[i]-ymin;
- mark(w,h,xt,yt,xt2,yt2,-k-1);
- /*
- printf("%f,%f -> ",(x[i]-xmin)*xscale,(y[i]-ymin)*yscale);
- printf("mark(%d,%d, %d,%d, %d,%d, %d)\n",w,h,xx,yy,xx2,yy2,zz);
- */
- xt=xt2; yt=yt2;
- i++;
- } while(i<=p_data[k]);
- k++;
- }
- /* printf("the first of the %d crossings before sorting\n",lc-1);
- for (i=2; i<9; i++) show_c(bo.cross_list[i]); getchar(); */
- /*---------------- sort list -------------*/
- hsort(&bo.cross_list[2],lc-2,sizeof(crossing),&compare);
- /*---------------- solve each problem -------------*/
- #ifdef DEBUG
- printf("crossings after sorting\n");
- for (i=2; i<9; i++) show_c(bo.cross_list[i]); getchar();
- #endif
- lb=1; /* bo.b_rule is empty */
- this=&bo.cross_list[2];
- last=&bo.cross_list[lc];
- while(this<last)
- {p=a;
- for (i=0; i<16; i++) p[i]=lhs[i];
- g=this->grid;
- #ifdef DEBUG
- printf("rule %d, boundary conditions for grid point %d\n",lb,g);
- #endif
- volt[g]=floor((p_voltage[-this->volt-1]-zmin)*zscale+.499);
- ru=&bo.b_rule[lb];
- ru->var[0]=g+1;
- ru->var[1]=g-1;
- ru->var[2]=g+w;
- ru->var[3]=g-w;
- do {j=this->direct;
- #ifdef DEBUG
- printf(" "); show_c(this);
- #endif
- f=this->dist;
- ru->var[j]=this->volt;
- a[j][0] *= f;
- a[j][1] *= f;
- a[j][2] *= f*f;
- this++;
- } while (this->grid == g);
- /* show_m("boundary condition matrix",a); getchar(); */
- cond=invert(4,4,a,ai);
- /* printf("condition number is %f\n",cond);
- show_m("matrix inverse",ai); */
- condp1=cond+1.;
- if(cond==condp1)
- {fprintf(stderr,
- "can\'t solve linear system for boundary conditions\n");
- exit(1);
- }
- for (i=0; i<4; i++) ru->coef[i]=ai[3][i]*SCALE+.5;
- if(LOWER_SIDE(g))
- {if(lower_symmetric)
- ru->coef[2] += ru->coef[3];
- else
- {weight=ru->coef[2]=(ru->coef[2] + ru->coef[3])/4;
- weight = SCALE - weight + ru->coef[0]+ru->coef[1];
- ru->coef[0] += weight/2;
- ru->coef[1] += weight - weight/2;
- }
- ru->coef[3]=0;
- }
- if(LEFT_SIDE(g))
- {if(left_symmetric)
- ru->coef[0] += ru->coef[1];
- else
- {weight=ru->coef[0]=(ru->coef[0] + ru->coef[1])/4;
- weight = SCALE - weight + ru->coef[2] + ru->coef[3];
- ru->coef[2] += weight/2;
- ru->coef[3] += weight - weight/2;
- }
- ru->coef[1]=0;
- }
- if(TOP_SIDE(g))
- {weight=ru->coef[3]=(ru->coef[2] + ru->coef[3])/4;
- weight = SCALE - weight + ru->coef[0]+ru->coef[1];
- ru->coef[1] += weight/2;
- ru->coef[0] += weight - weight/2;
- ru->coef[2]=0;
- }
- if(RIGHT_SIDE(g))
- {weight=ru->coef[1]=(ru->coef[1] + ru->coef[0])/4;
- weight = SCALE - weight + ru->coef[2]+ru->coef[3];
- ru->coef[2] += weight/2;
- ru->coef[3] += weight - weight/2;
- ru->coef[0]=0;
- }
- #ifdef DEBUG
- printf(" result is ");show_b(ru);
- #endif
- type[g]=-lb;
- lb++;
- }
-
- }
-
- compare(a,b) crossing *a,*b;
- { return (a->grid - b->grid);
- }
-
- mark (width,height,x1,y1,x2,y2,v) int width,height,v; double x1,y1,x2,y2;
- { int q,dx,dy,ax,ay,decide,up,over,i;
- int nx,nx2,ny,ny2;
- double del,xe,ye,f,t;
- /*
- if(x1<0||x1>=width||x2<0||x2>=width||y1<0||y1>=height||y2<0||y2>=height)
- {fprintf(stderr,"calling sequence error: mark(%d, %d,%d, %d,%d, %d)\n",
- width,x1,y1,x2,y2,v);
- fprintf(stderr,"(point outside 0<=x<%d or 0<=y<%d)\n",width,height);
- exit(1);
- }
- */
- #ifdef DEBUG
- printf("line from %5.2f,%5.2f to %5.2f,%5.2f at potential %5.2f\n",
- x1,y1,x2,y2,p_voltage[-v-1]);
- #endif
- if(x2<x1) {t=x1; x1=x2; x2=t; t=y1; y1=y2; y2=t;}
- nx2=x2*xscale;
- del=x2-x1;
- for (nx=x1*xscale+1; nx<=nx2; nx++)
- {xe=nx*edge;
- ye=(y1*(x2-xe) + y2*(xe-x1))/del;
- ny=ye*yscale;
- f=ye/edge-ny;
- #ifdef DEBUG
- printf(" crosses y grid line at %f,%f -> %d,%d at distance %f\n",xe,ye,nx,ny,f);
- #endif
- register_crossing(width,nx,ny,f,2,v);
- register_crossing(width,nx,ny+1,1.-f,3,v);
- }
- if(y2<y1) {t=x1; x1=x2; x2=t; t=y1; y1=y2; y2=t;}
- ny2=y2*yscale;
- del=y2-y1;
- for (ny=y1*yscale+1; ny<=ny2; ny++)
- {ye=ny*edge;
- xe=(x1*(y2-ye) + x2*(ye-y1))/del;
- nx=xe*xscale;
- f=xe/edge-nx;
- #ifdef DEBUG
- printf(" crosses x grid line at %f,%f -> %d,%d at distance %f\n",xe,ye,nx,ny,f);
- #endif
- register_crossing(width,nx,ny,f,0,v);
- register_crossing(width,nx+1,ny,1.-f,1,v);
- }
- }
-
- register_crossing(width,nx,ny,f,direction,v)
- int width,nx,ny,direction,v;
- double f;
- { crossing *new;
-
- if(lc>=MAX_CROSS) {fprintf(stderr,"too many boundary crosspoints\n"); exit(1);}
- new=&bo.cross_list[lc++];
- new->grid=nx+ny*width;
- new->direct=direction;
- new->dist=f;
- new->volt=v;
- }
-
- show_volt (type,volt,w,h) int *type; int *volt,w,h;
- { int i,j,k;
- k=0;
- printf("boundaries...");
- for (i=1; i<=boundaries; i++) printf("%d: %5.2f ",i,volt[-i]/zscale+zmin);
- printf("\n");
- /* printf("(press any key to abort printout)\n");
- for (i=0; i<h && !csts(); i++)
- */
- for (i=height-1; i>=0; i--)
- {k=i*w;
- printf("%3d: ",i);
- for (j=0; j<w; j++)
- {printf("%6.2f",volt[k++]/zscale+zmin);
- /* printf("%6d",volt[k++]); */
- }
- printf("\n");
- }
- for (i=height-1; i>=0; i--)
- {k=i*w+j;
- printf("%3d: ",i);
- for (j=0; j<width; j++)
- printf("%3d",type[k++]);
- printf("\n");
- }
- if(debugging) getchar();
- }
-
- read_data(argc,argv) int argc; char **argv;
- { int i,j,length;
- double xx,yy,d,*pd,sum;
- char *s,*t;
- #define BUFSIZE 200
- static char buf[BUFSIZE];
-
- x=malloc(ENTRIES*sizeof(double));
- y=malloc(ENTRIES*sizeof(double));
- if(x==0 || y==0) {fprintf(stderr,"can\'t allocate buffer"); exit();}
- if(argc>1 && streq(argv[1],"?")) help();
- if(argc<=1 || *argv[1]=='-') file=stdin;
- else
- {if(argc>1)
- {file=fopen(argv[1],"r");
- if(file==0) {printf("file %s not found\n",argv[1]); exit();}
- argc--; argv++;
- }
- else help();
- }
- argc--; argv++;
- while(argc>0)
- {i=get_parameter(argc,argv);
- argv=argv+i; argc=argc-i;
- }
- p_data[0]=-1;
- if(height<2||width<2||cycles<2)
- {fprintf(stderr,"parameter too small: height=%d, width=%d, cycles=%d",
- height,width,cycles);
- exit(1);
- }
- i=0;
- while(i<ENTRIES)
- {if(fgets(buf,BUFSIZE,file)==0) break;
- t=buf;
- while(*t && isspace(*t)) t++;
- if(*t == 0) continue; /* skip blank lines */
- buf[strlen(buf)-1]=0; /* zero out the line feed */
- if(buf[0]==';') {printf("%s\n",buf); continue;} /* skip comment */
- sscanf(buf,"%F %F",&x[i],&y[i]);
- if (x[i]<xmin) xmin=x[i];
- if (x[i]>xmax) xmax=x[i];
- if (y[i]<ymin) ymin=y[i];
- if (y[i]>ymax) ymax=y[i];
- s=buf; /* start looking for label */
- while(*s==' ')s++; /* skip first number */
- while(*s && (*s!=' '))s++;
- while(*s==' ')s++; /* skip second number */
- while(*s && (*s!=' '))s++;
- while(*s==' ')s++;
- if((length=strlen(s))&&(boundaries<MAXBOUNDARIES))
- {if(*s=='\"') s++; /* label in quotes */
- sscanf(s,"%F",&p_voltage[boundaries]);
- if(p_voltage[boundaries]<zmin) zmin=p_voltage[boundaries];
- if(p_voltage[boundaries]>zmax) zmax=p_voltage[boundaries];
- p_data[boundaries++]=i;
- }
- i++;
- }
- if(grounded)
- {if(0.<zmin) zmin=0.;
- if(0.>zmax) zmax=0.;
- }
- n=i;
- if(!boundaries || p_data[boundaries-1]!=n-1)
- {p_data[boundaries]=i-1;
- p_voltage[boundaries++]=0.;
- }
- xmin -= margin;
- xmax += margin;
- ymin -= margin;
- ymax += margin;
- }
-
-
- /* get_parameter - process one command line option
- (return # parameters used) */
- get_parameter(argc,argv) int argc; char **argv;
- { int i;
- double temp;
-
- if(streq(*argv,"-d")) {debugging=1; return 1;}
- else if(streq(*argv,"-h"))
- {if((argc>1) && numeric(argv[1])) height=atoi(argv[1]);
- return 2;
- }
- else if(streq(*argv,"-w"))
- {if((argc>1) && numeric(argv[1])) width=atoi(argv[1]);
- return 2;
- }
- else if(streq(*argv,"-g"))
- {grounded++;
- return 1;
- }
- else if(streq(*argv,"-m"))
- {i=get_double(argc,argv,1,&margin,&margin,&margin);
- if(margin<0.) margin=0.;
- return i;
- }
- else if(streq(*argv,"-n"))
- {if((argc>1) && numeric(argv[1])) cycles=atoi(argv[1]);
- return 2;
- }
- else if(streq(*argv,"-r"))
- {show_resid++;
- return 1;
- }
- else if(streq(*argv,"-b"))
- {show_boundaries++;
- return 1;
- }
- else if(streq(*argv,"-p"))
- {show_potentials++;
- return 1;
- }
- /* else if(streq(*argv,"-a"))
- {i=get_double(argc,argv,1,&temp,&temp,&temp);
- alpha=temp;
- alphap1=alpha+1;
- return i;
- }
- */
- else if(streq(*argv,"-x"))
- {i=get_double(argc,argv,2,&xmin,&xmax,&xmax);
- x_arguments=i-1;
- return i;
- }
- else if(streq(*argv,"-y"))
- {i=get_double(argc,argv,2,&ymin,&ymax,&ymax);
- y_arguments=i-1;
- return i;
- }
- else if(streq(*argv,"-xs"))
- {left_symmetric++;
- return 1;
- }
- else if(streq(*argv,"-ys"))
- {lower_symmetric++;
- return 1;
- }
- else gripe(argv);
- }
-
- get_double(argc,argv,permitted,a,b,c)
- int argc,permitted; char **argv; double *a,*b,*c;
- { int i=1;
- if((permitted--)>0 && (argc>i) && numeric(argv[i])) *a=atof(argv[i++]);
- if((permitted--)>0 && (argc>i) && numeric(argv[i])) *b=atof(argv[i++]);
- if((permitted--)>0 && (argc>i) && numeric(argv[i])) *c=atof(argv[i++]);
- return i;
- }
-
- int streq(a,b) char *a,*b;
- { while(*a)
- {if(*a!=*b)return 0;
- a++; b++;
- }
- return 1;
- }
-
- gripe_arg(s) char *s;
- { fprintf(stderr,"argument missing for switch %s",s);
- help();
- }
-
- gripe(argv) char **argv;
- { fprintf(stderr,*argv); fprintf(stderr," isn\'t a legal argument \n\n");
- help();
- }
-
- help()
- { fprintf(stderr,"laplace version %s",VERSION);
- fprintf(stderr,"\nusage: laplace [file][options]\n");
- fprintf(stderr,"options are:\n");
- /* fprintf(stderr," -a num acceleration factor (default %d) \n",alpha); */
- fprintf(stderr," -b display boundaries\n");
- fprintf(stderr," -g edge of grid is grounded (potential 0)\n");
- fprintf(stderr," -p display calculated potentials\n");
- fprintf(stderr," -r calculate and display residuals\n");
- fprintf(stderr," -m margin amount to expand grid beyond given boundaries (default 0) \n");
- fprintf(stderr," -n num number of relaxation cycles (default %d) \n",cycles);
- fprintf(stderr," -h num height of grid in cells (default %d)\n",height);
- fprintf(stderr," -w num width of grid in cells (default %d)\n",width);
- fprintf(stderr," -x [min [max]] specify x range \n");
- fprintf(stderr," -y [min [max]] specify y range \n");
- fprintf(stderr," -xs symmetric across the line x=xmin \n");
- fprintf(stderr," -ys symmetric across the line y=ymin \n");
- exit();
- }
-
- numeric(s) char *s;
- { char c;
- while(c=*s++)
- {if((c<='9' && c>='0') || c=='+' || c=='-' || c=='.') continue;
- return 0;
- }
- return 1;
- }
-
- #ifdef DESMET
-
- /*
- tics - report hundreths of a second since midnight
- */
-
- long tics()
- { int hr,min,sec,hun;
-
- _timer(&hr,&min,&sec,&hun);
- return (( (long) hr*60+min)*60+sec)*100+hun;
- }
-
- _timer()
- {
- #asm
- mov ah,2ch
- int 21h
- mov bx,[bp+4]
- mov [bx],ch ;hours
- mov byte [bx+1],0
- mov bx,[bp+6]
- mov [bx],cl ;minutes
- mov byte [bx+1],0
- mov bx,[bp+8]
- mov [bx],dh ;seconds
- mov byte [bx+1],0
- mov bx,[bp+10]
- mov [bx],dl ;hundreths
- mov byte [bx+1],0
- #endasm
- }
-
- #endif
-
- show_m(s,a) char *s; double *a;
- { int i,j;
- printf("%s\n",s);
- for (i=0; i<4; i++)
- {for (j=0; j<4; j++) printf("%8.2f ",*a++);
- printf("\n");
- }
- }
-